﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;

namespace DARE
{
    [AttrTypeDependentSerializable(typeof(CComboBoxData))]
    public class CComboBox : CWidget
    {
        #region fields

        private CListBox m_list;
        private CButton m_extendButton;
        private new CWidget m_selectedWidget;
        private float m_maxWidth;
        private int m_maxDisplayed;
        private Rectangle m_selectedRect;

        #endregion

        #region properties

        /// <summary>
        /// Gets/Sets the list in the CComboBox. This list is the list displayed when
        /// we click on the expend button.
        /// </summary>
        public CListBox List { get { return m_list; } set { m_list = value; } }

        /// <summary>
        /// Gets/Sets the selected widget of the list. This is the widget displayed in the CComboBox field
        /// </summary>
        public CWidget Selected
        {
            get { return m_list.SelectedInList; } 
            set
            {
                if (m_list != null && value != null)
                    m_list.SelectWidget(value);
            }
        }

        /// <summary>
        /// Gets/Sets the color of the highlight of the selected widget.
        /// </summary>
        public Color HLColor { get { return m_list.HLColor; } set { m_list.HLColor = value; } }

        /// <summary>
        /// Gets/Sets the max number of displayed widget in the list.
        /// When the number of widgets reaches the max number of displayed widget,
        /// a scrollbar is activated.
        /// </summary>
        public int MaxDisplayed
        {
            get { return m_maxDisplayed; }
            set
            {
                m_maxDisplayed = value;
                Rectangle r = m_list.Rect;
                r.Height = (int)(m_list.CWidgetHeight * m_maxDisplayed);
                m_list.Rect = r;
                Add(null);
            }
        }

        /// <summary>
        /// Gets/Sets the max width of the widget list
        /// </summary>
        public float MaxWidth
        {
            get { return m_maxWidth; }
            set
            {
                m_maxWidth = value;
                Vector2 tmp = m_list.Size;
                int max = m_list.getMaxWidthOfDisplayedList();
                if (max > m_maxWidth)
                    tmp.X = m_maxWidth;
                else
                    tmp.X = max;
                m_list.Size = tmp;
                Add(null);
            }
        }

        /// <summary>
        /// Gets the number of widgets in the list.
        /// </summary>
        public int Count { get { return m_list.Count; } }

        /// <summary>
        /// Gets/Sets the rectangle where the widget will be draw.
        /// This value is automatically set when the position and/or the size are set.
        /// If you plan to use a different rectangle than the one automatically created,
        /// we recommand you to use the UseDrawableRect and DrawableRect properties.
        /// </summary>
        /// <seealso cref="UseDrawableRect"/>
        /// <seealso cref="DrawableRect"/>
        public override Rectangle Rect
        {
            get
            {
                return base.Rect;
            }
            set
            {
                base.Rect = value;
                Actualize();
            }
        }

        /// <summary>
        /// If the value is between 0 and 1, the position is a percentage of the size of the parent
        /// (if the parent is null, the value is a percentage of the window).
        /// The value is relative to its parent.
        /// </summary>
        public override Vector2 Position
        {
            get
            {
                return base.Position;
            }
            set
            {
                base.Position = value;
                Actualize();
            }
        }

        /// <summary>
        /// If the value is between 0 and 1, the size is a percentage of the size of the parent
        /// (if the parent is null, the value is a percentage of the window).
        /// Else, the value is absolute.
        /// </summary>
        public override Vector2 Size
        {
            get
            {
                return base.Size;
            }
            set
            {
                base.Size = value;
                Actualize();
            }
        }

        public event eventMethod OnChange;

        #endregion

        #region actualize

        public override void Actualize()
        {
            base.Actualize();

            m_extendButton.Size = new Vector2(m_rect.Height, m_rect.Height);
            m_extendButton.Rect = new Rectangle(m_rect.X + m_rect.Width - m_rect.Height, m_rect.Y, m_rect.Height, m_rect.Height);
            m_list.Rect = new Rectangle(m_rect.X, m_rect.Y + m_rect.Height, (int)m_list.Size.X, (int)m_list.Size.Y);
            m_list.Actualize();
            m_selectedRect = new Rectangle((int)(m_rect.X + m_margins.Left), (int)(m_rect.Y + m_margins.Top), (int)(m_rect.Width - m_rect.Height - m_margins.Left - m_margins.Right), (int)(m_rect.Height - m_margins.Top - m_margins.Bottom));
        }

        #endregion

        #region Add

        /// <summary>
        /// Adds a widget to the CComboBox list
        /// </summary>
        public CComboBox Add(CWidget elem)
        {
            float width;
            float height;
            int inc = 0;
            if (elem != null)
                inc++;
            if (m_list.Count + inc <= m_maxDisplayed)
                height = (m_list.Count + inc) * m_list.CWidgetHeight;
            else
                height = m_maxDisplayed * m_list.CWidgetHeight;
            if (elem != null)
            {
                if (elem.Rect.Width > m_list.Rect.Width && elem.Rect.Width < m_maxWidth)
                    width = elem.Rect.Width;
                else if (elem.Rect.Width > m_maxWidth)
                    width = m_maxWidth;
                else
                    width = m_rect.Width;
            }
            else
                width = m_list.Rect.Width;
            m_list.Size = new Vector2(width, height);
            if (elem != null)
                m_list.Add(elem);
            Actualize();
            return this;
        }

        #endregion

        #region ctor

        public CComboBox(CHUDSystem hud, CWidget parent, string name)
            : base(hud, parent, name)
        {
            m_list = hud.GetElement("CComboBox_"+name+"_m_list") as CListBox;
            if (m_list == null)
            {
                m_list = new CListBox(HUD, null, "CComboBox_"+name+"_m_list");
                m_list.Position = new Vector2(m_rect.X, m_rect.Y + m_rect.Height);
                m_list.Size = new Vector2(0, 0);
                m_list.IsAlwaysOnTop = true;
                if (hud.Widgets.ContainsKey(m_list.Name))
                    hud.Remove(m_list.Name);
                hud.Add(m_list);
            }
            m_margins.Left = 2;
            m_margins.Top = 4;
            m_list.Hide();
            m_maxWidth = m_rect.Width;
            m_texture = HUD.Skinner.GetTexture("combobox");
            m_extendButton = new CButton(HUD, this, name + "_extend CButton");
            m_extendButton.Position = new Vector2(m_rect.Width - m_rect.Height, 0);
            m_extendButton.Size = new Vector2(m_rect.Height, m_rect.Height);

            m_extendButton.Texture = HUD.Skinner.GetTexture("comboboxextendbuttonreleased");
            m_extendButton.ReleasedTexture = HUD.Skinner.GetTexture("comboboxextendbuttonreleased");
            m_extendButton.ClickedTexture = HUD.Skinner.GetTexture("comboboxextendbuttonclicked");
            m_extendButton.OnClick += darker;
            m_extendButton.OnRelease += extend;
            m_maxDisplayed = 5;
            m_list.SelectWidget(0);

            m_selectedRect = new Rectangle((int)(m_rect.X + m_margins.Left), (int)(m_rect.Y + m_margins.Top), (int)(m_rect.Width - m_rect.Height - m_margins.Left - m_margins.Right), (int)(m_rect.Height - m_margins.Top - m_margins.Bottom));

            Size = new Vector2(150, 20);
        }

        #endregion

        #region events

        /// <summary>
        /// Gets a widget by its name
        /// </summary>
        public override CWidget GetElement(string name)
        {
            CWidget w = base.GetElement(name);
            if (w == null && m_list != null)
                w = m_list.GetElement(name);
            return w;
        }

        /// <summary>
        /// Checks if the mouse is over
        /// </summary>
        public override bool isMouseOver(CMouse mouse)
        {
            if (HUD.Cursor.IntersectionRect.Intersects(m_rect))
                return true;
            if (m_list.IsVisible && HUD.Cursor.IntersectionRect.Intersects(m_list.Rect))
                return true;
            /*if (mouse.Position.X >= m_rect.Left - 3 && mouse.Position.X <= m_rect.Right + 3 && mouse.Position.Y <= m_rect.Bottom + 3 && mouse.Position.Y >= m_rect.Top - 3)
                return true;*/
            return false;
        }

        /// <summary>
        /// Method called whenever the mouse is pressed and is over this widget
        /// </summary>
        public override bool onClick(CMouse mouse)
        {
            m_changed = false;
            if (m_list.IsVisible && m_list.isMouseOver(mouse))
            {
                m_activatedCWidget = m_list;
                CWidget wid = m_list.SelectedInList;
                bool ret = m_list.onClick(mouse);
                if (wid != m_list.SelectedInList)
                    m_changed = true;
                return ret;
            }
            return base.onClick(mouse);
        }
        private bool m_changed = false;
        public override bool onRelease(CMouse mouse)
        {
            if (m_list.IsVisible && m_list.isMouseOver(mouse))
            {
                if (m_changed)
                    OnChange.Invoke(this);
                m_selectedWidget = m_list.SelectedInList;
                extend(this);
            }
            return base.onRelease(mouse);
        }

        private void darker(CWidget sender)
        {
            if (CDare.Instance.InputMgr.Mouse.ButtonPressedEvent.First() == CMouse.EButton.LEFT)
                sender.Color = Color.Gray;
        }
        private bool isExtended = false;

        private void extend(CWidget sender)
        {
            if (CDare.Instance.InputMgr.Mouse.ButtonReleasedEvent.Count > 0 && CDare.Instance.InputMgr.Mouse.ButtonReleasedEvent.First() == CMouse.EButton.LEFT)
            {
                sender.Color = Color.White;
                if (!m_list.IsVisible)
                {
                    HUD.Detach(m_list);
                    HUD.Add(m_list);
                    m_list.Show();
                    isExtended = true;
                }
                else
                {
                    HUD.Detach(m_list);
                    m_list.Hide();
                    isExtended = false;
                }
            }
        }

        #endregion

        #region update/draw

        /// <summary>
        /// Hides this widget and all its children
        /// </summary>
        public override void Hide()
        {
            base.Hide();
            if (m_list != null)
                m_list.Hide();
            isExtended = false;
        }

        public override bool Update(GameTime gameTime)
        {
            if (!isExtended)
                m_list.Hide();
            if (!m_isVisible)
                return false;
               m_selectedWidget = m_list.SelectedInList;
            
//            m_list.Update(gameTime);
            return base.Update(gameTime);
        }

        public override bool Draw(GameTime gameTime)
        {
            if (!m_isVisible)
                return true;
            if (m_texture != null)
                m_texture.Draw(gameTime);//m_spriteBatch.Draw(m_texture, m_rect, m_color);
            Rectangle r;
            if (m_selectedWidget != null)
            {
                bool selectedVisible = m_selectedWidget.IsVisible;
                m_selectedWidget.Show();
                r = m_selectedWidget.Rect;
                m_selectedWidget.Rect = m_selectedRect;
                m_selectedWidget.Actualize();
                m_selectedWidget.Draw(gameTime);
                m_selectedWidget.Rect = r;
                m_selectedWidget.Actualize();
                if (!selectedVisible)
                    m_selectedWidget.Hide();
            }
            m_extendButton.Draw(gameTime);
            if (m_list.IsVisible)
            {
                HUD.Detach(m_list);
                HUD.Add(m_list);
//                m_list.Draw(gameTime);
            }
            return true;
        }

        #endregion
    }
}
